package cn.sc.summer.admin.notifier;

import cn.hutool.core.collection.CollUtil;
import cn.sc.summer.admin.enums.InstanceStatusEnum;
import cn.sc.summer.admin.properties.ServerProperties;
import com.alibaba.fastjson.JSONObject;
import cn.sc.summer.constant.rabbit.RabbitConstant;
import cn.sc.summer.constant.util.ConvertUtil;
import cn.sc.summer.rabbitmq.builder.RabbitBuilder;
import cn.sc.summer.rabbitmq.builder.RabbitMessageBuilderDirector;
import de.codecentric.boot.admin.server.domain.entities.Instance;
import de.codecentric.boot.admin.server.domain.entities.InstanceRepository;
import de.codecentric.boot.admin.server.domain.events.InstanceEvent;
import de.codecentric.boot.admin.server.domain.events.InstanceStatusChangedEvent;
import de.codecentric.boot.admin.server.domain.values.InstanceId;
import de.codecentric.boot.admin.server.domain.values.Registration;
import de.codecentric.boot.admin.server.notify.MailNotifier;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.lang.NonNull;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Service;
import org.thymeleaf.TemplateEngine;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 类名：服务实例变化消息发送
 *
 * @author a-xin
 * @date 2024/3/27 13:06
 */
@Slf4j
@Service
public class EmailNotifier extends MailNotifier {

    @Resource
    private RabbitTemplate rabbitTemplate;

    @Resource
    private ServerProperties serverProperties;

    @SuppressWarnings("all")
    public EmailNotifier(JavaMailSender mailSender, InstanceRepository repository, TemplateEngine templateEngine) {
        super(mailSender, repository, templateEngine);
    }

    @NonNull
    @Override
    protected Mono<Void> doNotify(@NonNull InstanceEvent event, @NonNull Instance instance) {
        String instanceName = instance.getRegistration().getName();
        InstanceId instanceId = event.getInstance();

        return Mono.fromRunnable(() -> {
            if (event instanceof InstanceStatusChangedEvent) {
                if (CollUtil.isEmpty(serverProperties.getIgnore())
                        || (CollUtil.isNotEmpty(serverProperties.getIgnore()) && !serverProperties.getIgnore().contains(instanceName) )) {
                    String status = ((InstanceStatusChangedEvent) event).getStatusInfo().getStatus();
                    Optional.ofNullable(InstanceStatusEnum.getByType(status))
                            .ifPresent(statusEnum -> {
                                switch (statusEnum) {
                                    case DOWN:
                                        log.error("==> The instance of {}(id = {}) is {}", instanceName, instanceId, status);
                                        break;
                                    case OFFLINE:
                                        log.error("==> The instance of {}(id = {}) is {}", instanceName, instanceId, status);
                                        break;
                                    case UP:
                                        log.warn("==> The instance of {}(id = {}) is {}", instanceName, instanceId, status);
                                        break;
                                    case UNKNOWN:
                                        log.error("==> The instance of {}(id = {}) is {}", instanceName, instanceId, status);
                                        break;
                                }
                                sendInstanceInfoEmail(instance, statusEnum);
                            });
                }
            } else {
                log.error("==> The instance of {}(id = {}) > {}", instanceName, instanceId, event.getType());
            }
        });
    }

    /**
     * 发送服务实例上下线消息邮件
     *
     * @param instance   实例信息
     * @param statusEnum 实例改变状态
     */
    private void sendInstanceInfoEmail(@NonNull Instance instance, @NonNull InstanceStatusEnum statusEnum) {
        String instanceName = instance.getRegistration().getName();
        Map<String, Object> data = new ConcurrentHashMap<>();
        data.put("serverName", instanceName);
        data.put("serverChangeType", statusEnum.getType());
        data.put("serverChangeDesc", statusEnum.getDesc());
        Registration registration = instance.getRegistration();
        Map<String, Object> registrationMap = ConvertUtil.convertToMap(registration);
        registrationMap.remove("metadata");
        registrationMap.putAll(registration.getMetadata());
        data.putAll(registrationMap);
        Map<String, Object> details = instance.getStatusInfo().getDetails();
        data.putAll(details);
        data.put("statusTimestamp", instance.getStatusTimestamp().toString());

        JSONObject message = new RabbitMessageBuilderDirector(new RabbitBuilder()).build();
        message.put(RabbitConstant.MESSAGE_KEY, JSONObject.toJSONString(data));
        rabbitTemplate.convertAndSend(
                RabbitConstant.EMAIL_SEND_EXCHANGE,
                RabbitConstant.EMAIL_SEND_ROUTING_KEY,
                message.toJSONString());
    }
}

